﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace mdk
{
    class Camera    // REFERENCIA: http://www.sgtconker.com/2010/09/article-simple-3d-camera-in-xna/
    {
        protected Matrix view, projection;

        public enum CameraMode { FREE, CHASE, ORBIT, Count };
        public CameraMode currentCameraMode = CameraMode.CHASE;
        
        private Vector3 position, target;           
        private Vector3 desiredPosition, desiredTarget, offsetDistance;

        private float yaw, pitch, roll;
        private float speed;
        private Matrix cameraRotation;
        
          /// <summary>
        /// Coordenadas da posição da camera
        /// </summary>
        public Vector3 Position
        {
            get { return position; }
        }

        /// <summary>
        /// 
        /// </summary>
        public Matrix View
        {
            get { return view; }
            set { View = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public Matrix Projection
        {
            get { return projection; }
            set { projection = value; }
        }

        public Camera(GraphicsDevice device)
        {
            ResetCamera();    
            
        }

        public void Update(Matrix chasedObjectsWorld)
        {
           
            HandleInput();
            UpdateViewMatrix(chasedObjectsWorld);

        }

        public void SwitchCameraMode()
        {

            ResetCamera();
            currentCameraMode++;

            if (currentCameraMode == CameraMode.Count)
                currentCameraMode = 0;

        }

        private void UpdateViewMatrix(Matrix chasedObjectsWorld)
        {
            
            switch (currentCameraMode)
            {
                case CameraMode.FREE:

                    cameraRotation.Forward.Normalize();
                    cameraRotation.Up.Normalize();
                    cameraRotation.Right.Normalize();
 
                    cameraRotation *= Matrix.CreateFromAxisAngle(cameraRotation.Right, pitch);
                    cameraRotation *= Matrix.CreateFromAxisAngle(cameraRotation.Up, yaw);
                    cameraRotation *= Matrix.CreateFromAxisAngle(cameraRotation.Forward, roll);
 
                    yaw = 0.0f;
                    pitch = 0.0f;
                    roll = 0.0f;
 
                    target = position + cameraRotation.Forward;

                    break;

                case CameraMode.CHASE:

                    cameraRotation.Forward.Normalize();
                    chasedObjectsWorld.Right.Normalize();
                    chasedObjectsWorld.Up.Normalize();
 
                    cameraRotation = Matrix.CreateFromAxisAngle(cameraRotation.Forward, roll);
 
                    desiredTarget = chasedObjectsWorld.Translation;
                    target = desiredTarget;
                    target += chasedObjectsWorld.Right * yaw;
                    target += chasedObjectsWorld.Up * pitch;
 
                    desiredPosition = Vector3.Transform(offsetDistance, chasedObjectsWorld);
                    position = Vector3.SmoothStep(position, desiredPosition, .25f);

 
                    yaw = MathHelper.SmoothStep(yaw, 0f, .1f);
                    pitch = MathHelper.SmoothStep(pitch, 0f, .1f);
                    roll = MathHelper.SmoothStep(roll, 0f, .2f);

                    break;

                case CameraMode.ORBIT:

                    cameraRotation.Forward.Normalize();
 
                    cameraRotation = Matrix.CreateRotationX(pitch) * Matrix.CreateRotationY(yaw) * Matrix.CreateFromAxisAngle(cameraRotation.Forward, roll);
 
                    desiredPosition = Vector3.Transform(offsetDistance, cameraRotation);
                    desiredPosition += chasedObjectsWorld.Translation;
                    position = desiredPosition;
 
                    target = chasedObjectsWorld.Translation;
 
                    roll = MathHelper.SmoothStep(roll, 0f, .2f);

                    break;
                
            }


            view = Matrix.CreateLookAt(position, target, cameraRotation.Up);           

           

        }

        private void ResetCamera()
        {
            
            position = new Vector3(0, 0, 50);
            target = Vector3.Zero;

            desiredPosition = position;
            desiredTarget = target;

            offsetDistance = new Vector3(0, 5, 20);

            yaw = 0.0f;
            pitch = 0.0f;
            roll = 0.0f;
 
            speed = .3f;
     
            cameraRotation = Matrix.Identity;

            view = Matrix.CreateLookAt(position, target, Vector3.Up);

            projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.PiOver4,
                    700 / 525,
                    1.0f,
                    100000.0f);     

        }

        private void HandleInput()
        {
            KeyboardState keyboardState = Keyboard.GetState();

            //Rotação da camera
            if (keyboardState.IsKeyDown(Keys.J))
            {
                yaw += .02f;
            }
            if (keyboardState.IsKeyDown(Keys.L))
            {
                yaw += -.02f;
            }
            if (keyboardState.IsKeyDown(Keys.I))
            {
                pitch += -.02f;
            }
            if (keyboardState.IsKeyDown(Keys.K))
            {
                pitch += .02f;
            }
            if (keyboardState.IsKeyDown(Keys.U))
            {
                roll += .02f;
            }
            if (keyboardState.IsKeyDown(Keys.O))
            {
                roll += -.02f;
            }
            

            if (currentCameraMode == CameraMode.FREE)
            {
                //Movimento da camera
                if (keyboardState.IsKeyDown(Keys.W))
                {
                    MoveCamera(cameraRotation.Forward);
                }
                if (keyboardState.IsKeyDown(Keys.S))
                {
                    MoveCamera(-cameraRotation.Forward);
                }
                if (keyboardState.IsKeyDown(Keys.A))
                {
                    MoveCamera(-cameraRotation.Right);
                }
                if (keyboardState.IsKeyDown(Keys.D))
                {
                    MoveCamera(cameraRotation.Right);
                }
                if (keyboardState.IsKeyDown(Keys.E))
                {
                    MoveCamera(cameraRotation.Up);
                }
                if (keyboardState.IsKeyDown(Keys.Q))
                {
                    MoveCamera(-cameraRotation.Up);
                }
                
            }            

        }

        private void MoveCamera(Vector3 addedVector)
        {
            position += speed * addedVector;
        }

        


    }
}
